import React from 'react';
import PropTypes from 'prop-types';
import css from './index.less';
import { observer } from 'mobx-react';
import { findSimulator } from 'common/utils/store';
import { stringExtendStyle } from 'common/utils/style';
import { computed } from 'mobx';
import Utils from 'common/utils';
import keycode from 'keycode';

const { addEvent, removeEvent } = Utils;


const UNLOCK_KEY_CODE = 'alt';
const DOT_SIZE = 7;
// todo 默认只提供四个点，另外四个点在元素旋转角度后，鼠标移动事件未按角度计算。
export const DOT_TYPE = [
/*  'left',
  'right',
  'top',
  'bottom', */
  'topLeft',
  'topRight',
  'bottomLeft',
  'bottomRight',
];
@observer
export default class Dot extends React.Component {
  static propTypes = {
    type: PropTypes.oneOf(DOT_TYPE).isRequired,
    mod: PropTypes.object.isRequired,
    // active: PropTypes.bool,
  };

  static defaultProps = {
  };

  constructor(props) {
    super(props);
    this.state = {
      startX: 0,
      startY: 0,
      startModWidth: 0,
      startModHeight: 0,
      startRectWidth: 0,
      startRectHeight: 0,
    };
  }

  componentDidMount() {
    this.onMouseMove = this.onMouseMove.bind(this);
    this.onMouseUp = this.onMouseUp.bind(this);
  }

  componentWillUnmount() {
    this.detachMouseEvent();
  }

  // todo 需计算当前元素旋转角度后的鼠标位移
  moveEvents = {
    left: (e) => {
      const { mod } = this.props;
      const { scale } = findSimulator(mod);
      const { startX, oriMod, oriRect } = this.state;
      const dif = startX - e.pageX;
      const rectW = oriRect.width + dif;
      if (rectW > 0) {
        mod.update({
          width: oriMod.width + dif / scale,
          left: oriMod.left - dif / scale,
        });
      }

    },
    right: (e) => {
      const { mod } = this.props;
      const { scale } = findSimulator(mod);
      const { startX, oriMod, oriRect } = this.state;
      const dif = e.pageX - startX;
      const rectW = oriRect.width + dif;
      if (rectW > 0) {
        mod.update({
          width: oriMod.width + dif / scale,
        });
      }
    },
    top: (e) => {
      const { mod } = this.props;
      const { scale } = findSimulator(mod);
      const { startY, oriMod, oriRect } = this.state;
      const dif = startY - e.pageY;
      const rectH = oriRect.height + dif;
      if (rectH > 0) {
        mod.update({
          height: oriMod.height + dif / scale,
          top: oriMod.top - dif / scale,
        });
      }
    },
    bottom: (e) => {
      const { mod } = this.props;
      const { scale } = findSimulator(mod);
      const { startY, oriMod, oriRect } = this.state;
      const dif = e.pageY - startY;
      const rectH = oriRect.height + dif;
      if (rectH > 0) {
        mod.update({
          height: oriMod.height + dif / scale,
        });
      }
    },
    topLeft: (e) => {
      const lockScale = CFG.hotKey.shift;
      const { mod } = this.props;
      const { scale } = findSimulator(mod);
      const { startX, startY, oriMod, oriRect } = this.state;
      const difX = startX - e.pageX;
      const difY = startY - e.pageY;
      const rectW = oriRect.width + difX;
      const rectH = oriRect.height + difY;
      if (rectW > 0 && rectH > 0) {
        const data = {
          height: oriMod.height + difY / scale,
          top: oriMod.top - difY / scale,
          width: oriMod.width + (lockScale ? difY : difX) / scale,
          left: oriMod.left - (lockScale ? difY : difX) / scale,
        };
        mod.update(data);
      }
    },
    topRight: (e) => {
      const lockScale = CFG.hotKey.shift;
      const { mod } = this.props;
      const { scale } = findSimulator(mod);
      const { startX, startY, oriMod, oriRect } = this.state;
      const difX = e.pageX - startX;
      const difY = startY - e.pageY;
      const rectW = oriRect.width + difX;
      const rectH = oriRect.height + difY;
      if (rectW > 0 && rectH > 0) {
        const data = {
          height: oriMod.height + difY / scale,
          top: oriMod.top - difY / scale,
          width: oriMod.width + (lockScale ? difY : difX) / scale,
        };
        mod.update(data);
      }
    },
    bottomLeft: (e) => {
      const lockScale = CFG.hotKey.shift;
      const { mod } = this.props;
      const { scale } = findSimulator(mod);
      const { startX, startY, oriMod, oriRect } = this.state;
      const difX = startX - e.pageX;
      const difY = e.pageY - startY;
      const rectW = oriRect.width + difX;
      const rectH = oriRect.height + difY;
      if (rectW > 0 && rectH > 0) {
        const data = {
          height: oriMod.height + difY / scale,
          width: oriMod.width + (lockScale ? difY : difX) / scale,
          left: oriMod.left - (lockScale ? difY : difX) / scale,
        };
        mod.update(data);
      }
    },
    bottomRight: (e) => {
      const lockScale = CFG.hotKey.shift;
      const { mod } = this.props;
      const { scale } = findSimulator(mod);
      const { startX, startY, oriMod, oriRect } = this.state;
      const difX = e.pageX - startX;
      const difY = e.pageY - startY;
      const rectW = oriRect.width + difX;
      const rectH = oriRect.height + difY;
      if (rectW > 0 && rectH > 0) {
        const data = {
          height: oriMod.height + difY / scale,
          width: oriMod.width + (lockScale ? difY : difX) / scale,
        };
        mod.update(data);
      }
    },
  };

  onMouseMove(e) {
    e.stopPropagation();
    e.preventDefault();
    const { type } = this.props;
    this.moveEvents[type](e);
  }

  onMouseUp(e) {
    e.stopPropagation();
    e.preventDefault();
    this.detachMouseEvent();
  }

  detachMouseEvent() {
    removeEvent(document, 'mousemove', this.onMouseMove);
    removeEvent(document, 'mouseup', this.onMouseUp);
    removeEvent(document, 'mouseleave', this.onMouseUp);
  }

  @computed get position() {
    const { mod, mod: { rect: { width, height, left, top } } } = this.props;
    const { scrollTop } = findSimulator(mod);
    return {
      top: top - scrollTop - DOT_SIZE / 2,
      bottom: top + height - scrollTop - DOT_SIZE / 2,
      left: left - DOT_SIZE / 2,
      right: left + width - DOT_SIZE / 2,
      center: left - DOT_SIZE + width / 2, // 横向居中
      middle: top - DOT_SIZE - scrollTop + height / 2, // 纵向居中
    };
  }

  @computed get style() {
    const { type, mod: { rotate, rect: { width, height } } } = this.props; // type: 'topLeft' etc..
    // console.log('width:', this.props.mod);
    const { left, right, top, bottom, middle, center } = this.position;
    let style = {
      width: DOT_SIZE,
      height: DOT_SIZE,
      transform: stringExtendStyle([
        {
          key: 'rotate',
          val: rotate
        }
      ]),
    };

    const halfWidth1 = parseInt((width + DOT_SIZE) / 2); // 须取整，避免变形后线条模糊
    const halfWidth2 = parseInt((width - DOT_SIZE) / 2);
    const halfHeight1 = parseInt((height + DOT_SIZE) / 2);
    const halfHeight2 = parseInt((height - DOT_SIZE) / 2);
    switch (type) {
      case 'left': {
        style = {
          ...style,
          left,
          top: middle,
          transformOrigin: `${halfWidth1}px ${DOT_SIZE}px`,
        };
        break;
      }
      case 'right': {
        style = {
          ...style,
          left: right,
          top: middle,
          transformOrigin: `-${halfWidth2}px ${DOT_SIZE}px`,
        };
        break;
      }
      case 'top': {
        style = {
          ...style,
          left: center,
          top: top,
          transformOrigin: `${DOT_SIZE}px ${halfHeight1}px`,
        };
        break;
      }
      case 'bottom': {
        style = {
          ...style,
          left: center,
          top: bottom,
          transformOrigin: `${DOT_SIZE}px -${halfHeight2}px`,
        };
        break;
      }
      case 'topLeft': {
        style = {
          ...style,
          left: left,
          top: top,
          transformOrigin: `${halfWidth1}px ${halfHeight1}px`,
        };
        break;
      }
      case 'topRight': {
        style = {
          ...style,
          left: right,
          top: top,
          transformOrigin: `-${halfWidth2}px ${halfHeight1}px`,
        };
        break;
      }
      case 'bottomLeft': {
        style = {
          ...style,
          left: left,
          top: bottom,
          transformOrigin: `${halfWidth1}px -${halfHeight2}px`,
        };
        break;
      }
      case 'bottomRight': {
        style = {
          ...style,
          left: right,
          top: bottom,
          transformOrigin: `-${halfWidth2}px -${halfHeight2}px`,
        };
        break;
      }
    }
    return style;
  }

  render() {
    const { mod, mod: { rect }, style, topPosition = 0 } = this.props;
    if (topPosition) {
      this.style.top -= topPosition;
    }
    const props = {
      className: css.dot,
      style: {
        ...this.style,
        ...style
      },
      onMouseDown: (e) => {
        e.stopPropagation();
        e.preventDefault();
        this.setState({
          startX: e.pageX,
          startY: e.pageY,
          oriMod: {
            width: mod.width,
            height: mod.height,
            left: mod.left,
            top: mod.top,
          },
          oriRect: {
            ...rect,
          },
        });
        addEvent(document, 'mousemove', this.onMouseMove);
        addEvent(document, 'mouseup', this.onMouseUp);
        addEvent(document, 'mouseleave', this.onMouseUp);
      }
    };

    return (
      <div {...props} />
    );
  }
}
